package net.sf.rose.file.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import freemarker.template.Configuration;
import freemarker.template.Template;
import net.sf.rose.boot.BootStrap;
import net.sf.rose.file.monitor.FileMonitor;
import net.sf.rose.file.monitor.FileMonitorReocrd;
import net.sf.rose.util.RoseRuntimeException;
import org.apache.commons.codec.binary.Base64;

/**
 * @description：集成对文件及文件路径的操作
 * @author fengjian E-mail: 9110530@qq.com
 * @version 创建时间：2015年9月30日 上午9:59:45
 */
@SuppressWarnings("all")
public class FileUtils {

	private static Logger LOG = Logger.getLogger(FileUtils.class);

	/**
	 * 获取资源文件输入流
	 * 
	 * @param fileName 文件名
	 * @return 文件输入流
	 */
	public static InputStream getFileInputStream(String fileName) {
		InputStream in = null;
		// 先从工程根目录下找
		File file = BootStrap.getSystemFile(fileName);
		if (file.exists()) {
			try {
				System.out.println("读取资源文件:" + file.getAbsolutePath());
				return new FileInputStream(file);
			} catch (FileNotFoundException e) {
			}
		}
		// 如果没有找到就从jar包里找
		else {
			in = FileUtils.class.getClassLoader().getResourceAsStream(fileName);
			if (in != null) {
				System.out.println("从jar包中读取资源文件:" + fileName);
			}
		}
		return in;
	}

	/**
	 * 获取资源文件输入流
	 * 
	 * @param fileName 文件名
	 * @return 文件输入流
	 */
	public static Properties getFileProperties(String fileName) {
		InputStream in = getFileInputStream(fileName);
		Properties properties = new Properties();
		try {
			properties.load(in);
			in.close();
		} catch (Exception e) {
			throw new RoseRuntimeException(e);
		}
		return properties;
	}

	/**
	 * 根据图片文件相对路径生成图片文件对象
	 * 
	 * @param url - 图片文件相对路径
	 * @return 图片文件对象
	 */
	public static File getImageFile(String url) {
		File file = url.indexOf("images") != -1 ? IMAGE_PATH.getParentFile() : IMAGE_PATH;
		return new File(file, url);
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param file - 文件
	 * @return 文件是否存在
	 */
	public static boolean exists(File file) {
		return file.exists() ? true : false;
	}

	/**
	 * 创建文件夹
	 * 
	 * @param file - 文件夹路径
	 */
	public static void creatDirectory(File file) {
		if (!exists(file)) {
			file.mkdirs();
		}
	}

	/**
	 * 创建文件夹
	 * 
	 * @param strPath - 文件夹路径
	 */
	public static void creatDirectory(String strPath) {
		File file = new File(strPath);
		creatDirectory(file);
	}

	/**
	 * 创建文件
	 * 
	 * @param file - 文件
	 * @throws IOException - 文件创建失败时抛出异常
	 */
	public static void creatFile(File file) throws IOException {
		if (!exists(file)) {
			file.createNewFile();
		}
	}

	/**
	 * 创建文件
	 * 
	 * @param strFileName - 文件
	 * @throws IOException - 文件创建失败时抛出异常
	 */
	public static void creatFile(String strFileName) throws IOException {
		File file = new File(strFileName);
		creatFile(file);
	}

	/**
	 * 删除文件
	 * 
	 * @param file - 文件
	 */
	public static void deleteFile(File file) {
		if (file.isFile()) {
			file.delete();
		}
	}

	/**
	 * 删除文件
	 * 
	 * @param strFileName - 文件
	 */
	public static void deleteFile(String strFileName) {
		File file = new File(strFileName);
		deleteFile(file);
	}

	/**
	 * 删除路径或文件
	 * 
	 * @param file - 文件
	 */
	private static void deleteAllOfDirectory(File file) {
		File[] files = file.listFiles();
		if (files != null && files.length > 0) {
			for (int i = 0; i < files.length; i++) {
				deleteAllOfDirectory(files[i]);
			}
		}
		file.delete();
	}

	/**
	 * 深度删除路径或文件
	 * 
	 * @param file - 文件
	 */
	public static void deleteDirectory(File file) {
		if (file.isDirectory()) {
			deleteAllOfDirectory(file);
		}
	}

	/**
	 * 深度删除路径或文件
	 * 
	 * @param strPath - 文件
	 */
	public static void deleteDirectory(String strPath) {
		File file = new File(strPath);
		deleteDirectory(file);
	}

	/**
	 * 将字符串转换为数据流
	 * 
	 * @param string - 字符串
	 * @return - 数据流
	 */
	public static InputStream toInputStream(String string) {
		return new ByteArrayInputStream(string.getBytes());
	}

	/**
	 * 将二进制流转换为数据流
	 * 
	 * @param buf - 二进制流
	 * @return - 数据流
	 */
	public static InputStream toInputStream(byte[] buf) {
		return new ByteArrayInputStream(buf);
	}

	/**
	 * 复制数据流
	 * 
	 * @param in  - 输入数据流
	 * @param out - 输出数据流
	 * @throws IOException - 数据流复制异常时抛出
	 */
	public static void copy(InputStream in, OutputStream out) throws IOException {
		// Transfer bytes from in to out
		byte[] buf = new byte[1024];
		int len;
		while ((len = in.read(buf)) > 0) {
			out.write(buf, 0, len);
		}
		in.close();
		out.close();
	}

	/**
	 * 文件复制
	 * 
	 * @param src - 源文件
	 * @param dst - 目标文件
	 * @throws IOException - 文件复制异常时抛出异常
	 */
	public static void copy(File src, File dst) throws IOException {
		InputStream in = new FileInputStream(src);
		OutputStream out = new FileOutputStream(dst);
		copy(in, out);
	}

	/**
	 * 复制对象
	 * 
	 * @param object - 源对象
	 * @return 复制的对象
	 * @throws Exception - 复制过程中发生异常
	 */
	public static Object copy(Object object) throws Exception {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		ObjectOutput out = new ObjectOutputStream(bout);
		out.writeObject(object);

		ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
		ObjectInputStream in = new ObjectInputStream(bin);
		object = in.readObject();

		bout.close();
		bin.close();
		in.close();
		out.close();
		return object;
	}

	/**
	 * 从文件读入二进制流
	 * 
	 * @param file - 文件
	 * @return 二进制流
	 * @throws IOException 转换时异常
	 */
	public static byte[] toByteArray(File file) throws IOException {
		byte[] bytes = null;
		FileInputStream fis = null;
		fis = new FileInputStream(file);
		FileChannel c = fis.getChannel();
		ByteBuffer bc = ByteBuffer.allocate((int) c.size());
		int i = c.read(bc);
		if (i != -1) {
			bytes = bc.array();
		}
		c.close();
		fis.close();
		return bytes;
	}

	/**
	 * 将二进制流转化成字节数组
	 * 
	 * @param inStream - 文件流
	 * @return 二进制流
	 * @throws IOException 文件流操作异常
	 */
	public static byte[] toByteArray(InputStream inStream) throws IOException {
		ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
		byte[] buff = new byte[100];
		int rc = 0;
		while ((rc = inStream.read(buff, 0, 100)) > 0) {
			swapStream.write(buff, 0, rc);
		}
		return swapStream.toByteArray();
	}

	/**
	 * 将文件转化成字符串
	 * 
	 * @param file - 文件对象
	 * @return 字符串
	 * @throws IOException 文件流操作异常
	 */
	public static String toString(File file) throws IOException {
		return toString(new FileInputStream(file));
	}

	/**
	 * 将二进制流转化成字符串
	 * 
	 * @param inStream - 文件流
	 * @return 字符串
	 * @throws IOException 文件流操作异常
	 */
	public static String toString(InputStream inStream) throws IOException {
		StringBuilder sb = new StringBuilder();
		BufferedReader in = null;
		in = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
		String str;
		while ((str = in.readLine()) != null) {
			sb.append(str).append('\n');
		}
		in.close();
		return sb.toString();
	}

	/**
	 * 根据指定freemaker的模板文件和数据生成结果文件
	 * 
	 * @param fileName 模板文件名,例：freemaker\\test.ftl
	 * @param model    数据模型
	 * @param file     输出文件名
	 * @return 是否创建成功
	 */
	public static boolean createFreemakerFile(String fileName, Map<String, Object> model, File file) {
		// 创建一个Configuration对象，直接new一个对象。构造方法的参数就是freemarker对于的版本号。
		Configuration configuration = new Configuration(Configuration.getVersion());
		// 设置模板文件使用的字符集。一般就是utf-8.
		configuration.setDefaultEncoding("utf-8");
		configuration.setOutputEncoding("utf-8");
		Writer out = null;
		try {
			File mf = BootStrap.getResourceFile(fileName);
			// 设置模板文件所在的路径。
			configuration.setDirectoryForTemplateLoading(mf.getParentFile());
			// 加载一个模板，创建一个模板对象。
			Template template = configuration.getTemplate(mf.getName());
			// 创建一个Writer对象，一般创建一FileWriter对象，指定生成的文件名。
			out = new FileWriter(file);
			// 第七步：调用模板对象的process方法输出文件。
			template.process(model, out);
			// 第八步：关闭流。
			out.close();
			out = null;
			LOG.info("根据模板文件合成文件" + file.getAbsolutePath() + "已成功...");
		} catch (Exception e) {
			String mess = "根据模板文件合成文件" + file.getAbsolutePath() + "时发生异常！\n" + e.getMessage();
			LOG.error(mess, e);
			throw new RoseRuntimeException(mess);
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
				}
			}
		}
		return true;
	}

	/**
	 * 将源文件保存至指定文件
	 * 
	 * @param file - 指定的文件
	 * @param code - 源代码字符串
	 */
	public static void saveFile(File file, String code) {
		try {
			OutputStreamWriter op = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
			op.append(code);
			op.flush();
			op.close();
		} catch (Exception e) {
			String str = "源代码保存失败！\n" + e.getMessage();
			throw new RoseRuntimeException(str + e);
		}
	}

	/**
	 * 初始化查找Java源文件路径以及Class文件路径
	 */
	public static void initial() {
		File file = BootStrap.getResourcePath().getParentFile();
		// 从根目录开始搜索子文件夹，找到Java源文件、class文件
		File[] files = new File[] { null, null };
		for (File f : file.listFiles()) {
			readFile(f, files);
			if (files[0] != null && files[1] != null) {
				break;
			}
		}
		// 如果找到了Java源文件、class文件
		if (files[0] != null && files[1] != null) {
			try {
				// 读取Java源文件中的包名称
				String str = FileUtils.toString(files[0]);
				str = str.substring(0, str.indexOf(';'));
				str = str.substring(str.indexOf(' '));
				str = str.trim();
				// 根据包名将当前文件所在的文件夹往上级目录找到Java文件的根目录
				int size = StringUtils.split(str, '.').length;
				file = files[0];
				for (int i = 0; i <= size; i++) {
					file = file.getParentFile();
				}
				JAVA_SOURCE_PATH = file.getAbsoluteFile();
				System.out.println("系统找到Java源文件的路径：" + JAVA_SOURCE_PATH);
				// 往上级找文件夹名称为classes的文件夹作为class文件的根目录
				file = files[1];
				file = file.getParentFile();
				while (!file.getName().equals("classes")) {
					file = file.getParentFile();
				}
				JAVA_CLASS_PATH = file.getAbsoluteFile();
				System.out.println("系统找到class文件的路径：" + JAVA_CLASS_PATH);
				// 监控classes文件夹的变化情况
				if (JAVA_CLASS_PATH != null && JAVA_CLASS_PATH.exists()) {
					File path = FileUtils.JAVA_CLASS_PATH;
					File file2 = new File(BootStrap.getResourcePath().getParent(), "fileModifyRecord.txt");
					if (FileMonitorReocrd.setRecordFile(file2)) {
						FileMonitor.start(path, new FileMonitorReocrd());
					}
				}
			} catch (Exception e) {
				throw new RoseRuntimeException(e);
			}
		}
	}

	/**
	 * 遍历目录读取1个java文件和1个class文件路径
	 * 
	 * @param path  - 要查找的文件目录
	 * @param files - 返回的文件列表
	 */
	private static void readFile(File path, File[] files) {
		if (path.isDirectory()) {
			for (File f : path.listFiles()) {
				readFile(f, files);
				if (files[0] != null && files[1] != null) {
					return;
				}
			}
		} else {
			String name = path.getName();
			int i = name.lastIndexOf('.');
			if (i != -1) {
				name = name.substring(i);
				if (name.equals(".java") && files[0] == null) {
					files[0] = path;
					System.out.println("系统找到1个Java文件的路径：" + files[0]);
				} else if (name.equals(".class") && files[1] == null) {
					files[1] = path;
					System.out.println("系统找到1个class文件的路径：" + files[1]);
				}
			}
		}
	}

	/**
	 * 图片转base64字符串
	 *
	 * @param imgFile 图片路径
	 * @return
	 */
	public static String imageToBase64Str(File imgFile) {
		InputStream inputStream = null;
		byte[] data = null;
		try {
			inputStream = new FileInputStream(imgFile);
			data = new byte[inputStream.available()];
			inputStream.read(data);
			inputStream.close();
			Base64 base64 = new Base64();
			return base64.encodeBase64String(data);
		} catch (IOException e) {
			throw new RoseRuntimeException(e.getMessage(), e);
		}
	}

	/**
	 * base64编码字符串转换为图片,并写入文件
	 *
	 * @param strImage base64编码字符串
	 * @param file     图片路径
	 * @return
	 */
	public static boolean base64StrToImage(String strImage, File file) {
		if (strImage == null)
			return false;
		try {
			Base64 base64 = new Base64();
			byte[] b = base64.decodeBase64(strImage);
			// 处理数据
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0) {
					b[i] += 256;
				}
			}
			// 文件夹不存在则自动创建
			OutputStream out = new FileOutputStream(file);
			out.write(b);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public static void main(String[] args) throws Exception {
		String str = toString(FileUtils.class.getResourceAsStream("image.txt"));
		base64StrToImage(str, new File("c:/aa.image"));
	}

	/** 图片文件存储路径 */
	public static File IMAGE_PATH = null;

	/** 前端页面存储路径 */
	public static File WEB_APP_PATH = null;

	/** java源文件的存储路径 */
	public static File JAVA_SOURCE_PATH = null;

	/** java编绎文件的存储路径 */
	public static File JAVA_CLASS_PATH = null;

}
